package com.coderg.gmall.cart.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.coderg.gmall.cart.mapper.CartInfoMapper;
import com.coderg.gmall.cart.service.CartService;
import com.coderg.gmall.cart.util.GmallThreadLocalUtils;
import com.coderg.gmall.common.constant.CartConst;
import com.coderg.gmall.common.constant.RedisConst;
import com.coderg.gmall.model.cart.CartInfo;
import com.coderg.gmall.model.product.SkuInfo;
import com.coderg.gmall.product.ItemProductFeign;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RReadWriteLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

/**
 * @Description
 * @Author CoderG
 * @Date 2025/6/2 15:20
 **/
@Service
@Slf4j
public class CartServiceImpl implements CartService {

    @Autowired
    CartInfoMapper cartInfoMapper;
    @Autowired
    ItemProductFeign itemFeign;
    @Autowired
    ThreadPoolExecutor threadPoolExecutor;
    @Autowired
    RedisTemplate<Object, Object> redisTemplate;
    @Autowired
    RedissonClient redissonClient;

    private final ExecutorService asyncExecutor = Executors.newFixedThreadPool(4);


    /**
     * 添加、更新 购物车  比较粗糙的一种写法
     *
     * @param skuId
     * @param goodsNumber
     */

    public void addCart1(Long skuId, Long goodsNumber) {

        String username = GmallThreadLocalUtils.getUserName();
        //redisKey
        String key = RedisConst.USER_KEY_PREFIX + username + RedisConst.USER_CART_KEY_SUFFIX;

        if (skuId == null || goodsNumber == null) {
            throw new RuntimeException("参数错误");
        }
        //查询用户是否已经有这个购物车  没有新增 有 改数量
        CartInfo cartOne = cartInfoMapper.selectOne(
                new LambdaQueryWrapper<CartInfo>()
                        .eq(CartInfo::getUserId, username)
                        .eq(CartInfo::getSkuId, skuId)
        );
        //新增
        if (cartOne == null || cartOne.getId() == null) {
            if (goodsNumber <= 0) {
                return;
            }
            //查询商品信息
            CartInfo cartInfo = new CartInfo();
            SkuInfo skuInfo = itemFeign.getSkuInfo(skuId);
            cartInfo.setUserId(username);
            cartInfo.setSkuId(skuId);
            cartInfo.setImgUrl(skuInfo.getSkuDefaultImg());
            cartInfo.setSkuName(skuInfo.getSkuName());
            cartInfo.setSkuNum(goodsNumber.intValue());
            //查询最新价格
            BigDecimal skuPrice = itemFeign.getSkuPrice(skuId);
            cartInfo.setCartPrice(skuPrice);
            cartInfo.setIsChecked((short) 1);
            //保存
            int insert = cartInfoMapper.insert(cartInfo);
            if (insert < 0) {
                throw new RuntimeException("添加失败");
            }

        } else {
            //合并数量<=0 删除
            if ((cartOne.getSkuNum() + goodsNumber) <= 0) {
                cartInfoMapper.deleteById(cartOne.getId());
                //更新缓存
                redisTemplate.opsForHash().delete(key, cartOne.getSkuId().toString());
            }
            //数量>0更新
            cartOne.setSkuNum(cartOne.getSkuNum() + goodsNumber.intValue());
            int update = cartInfoMapper.updateById(cartOne);
            if (update < 0) {
                throw new RuntimeException("添加失败");
            }
        }


    }

    /**
     * redission 读写锁 强一致性 缓存
     *
     * @param skuId
     * @param goodsNumber
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addCart(Long skuId, Long goodsNumber) {
        /**
         * 写锁 排它锁  实现 写缓存
         */
        // 1. 参数校验
        if (skuId == null || goodsNumber == null || goodsNumber == 0) {
            throw new IllegalArgumentException("参数错误");
        }
        String username = GmallThreadLocalUtils.getUserName();
        String key = RedisConst.USER_KEY_PREFIX + username + RedisConst.USER_CART_KEY_SUFFIX;

        try {
            // 2. 查询现有购物车项
            CartInfo existingCart = cartInfoMapper.selectOne(
                    new LambdaQueryWrapper<CartInfo>()
                            .eq(CartInfo::getUserId, username)
                            .eq(CartInfo::getSkuId, skuId)
            );
            //创建锁
            RReadWriteLock readWriteLock = redissonClient.
                    getReadWriteLock("lock-read-write" + username);
            RLock writeLock = readWriteLock.writeLock();
            try {
                //加锁
                writeLock.lock();
                if (existingCart == null) {
                    // 新增逻辑
                    handleAddNewCartItem(skuId, goodsNumber, username, key);
                } else {
                    // 更新逻辑
                    handleUpdateCartItem(existingCart, goodsNumber, key, username);
                }
                deleteCache(key);
            } catch (Exception e) {
                e.printStackTrace();
                throw e;
            } finally {
                writeLock.unlock();
            }
        } catch (Exception e) {
            log.error("购物车操作失败，用户: {}, skuId: {}", username, skuId, e);
            throw new RuntimeException("购物车操作失败");
        }

    }

    /**
     * 添加、更新 购物车
     * 没有带重试的延迟双删
     *
     * @param skuId
     * @param goodsNumber
     */
    @Transactional(rollbackFor = Exception.class)
    public void addCart2(Long skuId, Long goodsNumber) {
        // 1. 参数校验
        if (skuId == null || goodsNumber == null || goodsNumber == 0) {
            throw new IllegalArgumentException("参数错误");
        }

        String username = GmallThreadLocalUtils.getUserName();
        String key = RedisConst.USER_KEY_PREFIX + username + RedisConst.USER_CART_KEY_SUFFIX;

        try {
            // 2. 查询现有购物车项
            CartInfo existingCart = cartInfoMapper.selectOne(
                    new LambdaQueryWrapper<CartInfo>()
                            .eq(CartInfo::getUserId, username)
                            .eq(CartInfo::getSkuId, skuId)
            );

            // 3. 第一次删除缓存
            deleteCache(key);

            if (existingCart == null) {
                // 新增逻辑
                handleAddNewCartItem(skuId, goodsNumber, username, key);
            } else {
                // 更新逻辑
                handleUpdateCartItem(existingCart, goodsNumber, key, username);
            }

            // 4. 异步延迟删除缓存
            scheduleDelayDelete(key);
        } catch (Exception e) {
            log.error("购物车操作失败，用户: {}, skuId: {}", username, skuId, e);
            throw new RuntimeException("购物车操作失败");
        }
    }

    private void handleAddNewCartItem(Long skuId, Long goodsNumber, String username, String key) {
        if (goodsNumber < 0) {
            return;
        }

        // 查询商品信息
        SkuInfo skuInfo = itemFeign.getSkuInfo(skuId);
        BigDecimal skuPrice = itemFeign.getSkuPrice(skuId);

        // 构建新购物车项
        CartInfo newCart = new CartInfo();
        newCart.setUserId(username);
        newCart.setSkuId(skuId);
        newCart.setImgUrl(skuInfo.getSkuDefaultImg());
        newCart.setSkuName(skuInfo.getSkuName());
        newCart.setSkuNum(goodsNumber.intValue());
        newCart.setCartPrice(skuPrice);
        newCart.setIsChecked((short) 1);

        // 保存到数据库
        if (cartInfoMapper.insert(newCart) <= 0) {
            throw new RuntimeException("添加购物车失败");
        }
    }

    private void handleUpdateCartItem(CartInfo existingCart, Long goodsNumber, String key, String username) {
        int newQuantity = existingCart.getSkuNum() + goodsNumber.intValue();

        if (newQuantity <= 0) {
            // 删除逻辑
            if (cartInfoMapper.deleteById(existingCart.getId()) <= 0) {
                throw new RuntimeException("删除购物车项失败");
            }
        } else {
            // 更新逻辑
            existingCart.setSkuNum(newQuantity);
            if (cartInfoMapper.updateById(existingCart) <= 0) {
                throw new RuntimeException("更新购物车失败");
            }
        }
    }

    private void scheduleDelayDelete(String key) {
        asyncExecutor.execute(() -> {
            try {
                Thread.sleep(500); // 延迟500ms
                deleteCache(key);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                log.warn("延迟双删被中断，key: {}", key);
            }
        });
    }

    private void deleteCache(String key) {
        try {
            redisTemplate.delete(key);
        } catch (Exception e) {
            log.error("删除缓存失败，key: {}, skuId: {}", key, e);
        }
    }


    /**
     * 查询购物车
     *
     * @return
     */
    public List<CartInfo> getCarts1() {
        String username = GmallThreadLocalUtils.getUserName();
        //查缓存
        String key = RedisConst.USER_KEY_PREFIX + username + RedisConst.USER_CART_KEY_SUFFIX;

        Map<Object, Object> cartInfoMap = redisTemplate.opsForHash().entries(key);
        //有缓存
        if (!cartInfoMap.isEmpty()) {
            List<CartInfo> cartInfos = cartInfoMap.entrySet().stream().map(cartInfo -> JSONObject.
                    parseObject((String) cartInfo.getValue(), CartInfo.class)).collect(Collectors.toList());
            return cartInfos;
        }
        //无缓存 查数据库
        LambdaQueryWrapper<CartInfo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(CartInfo::getUserId, username);
        List<CartInfo> cartInfos = cartInfoMapper.selectList(queryWrapper);
        //放入redis
        // set (user:1:cart) hset(skuId,CartInfoJson)
        try {
            if (cartInfos != null && !cartInfos.isEmpty()) {
                //更新缓存
                putToCache(cartInfos, key);
            } else {
                CartInfo cartInfo = new CartInfo();
                redisTemplate.opsForHash().put(key, -1, JSONObject.toJSONString(cartInfo));
                cartInfos = Collections.emptyList();
            }
        } catch (Exception e) {
            log.error("更新购物车缓存异常，key: {}, 异常信息: {}", key, e.getMessage(), e);
        } finally {
            redisTemplate.expire(key, 60 * 24, TimeUnit.MINUTES);
        }
        return cartInfos;
    }

    /**
     * 查询购物车
     *
     * @return
     */
    @Override
    public List<CartInfo> getCarts() {

        String username = GmallThreadLocalUtils.getUserName();
        //查缓存
        String key = RedisConst.USER_KEY_PREFIX + username + RedisConst.USER_CART_KEY_SUFFIX;

        Map<Object, Object> cartInfoMap = redisTemplate.opsForHash().entries(key);
        //有缓存
        if (!cartInfoMap.isEmpty()) {
            List<CartInfo> cartInfos = cartInfoMap.entrySet().stream().map(cartInfo -> JSONObject.
                    parseObject((String) cartInfo.getValue(), CartInfo.class)).collect(Collectors.toList());
            return cartInfos;
        }
        //创建锁
        RReadWriteLock readWriteLock = redissonClient.
                getReadWriteLock("lock-read-write" + username);
        RLock readLock = readWriteLock.readLock();
        try {
            readLock.lock();
            //无缓存 查数据库
            LambdaQueryWrapper<CartInfo> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(CartInfo::getUserId, username);
            List<CartInfo> cartInfos = cartInfoMapper.selectList(queryWrapper);
            //放入redis
            // set (user:1:cart) hset(skuId,CartInfoJson)
            try {
                if (cartInfos != null && !cartInfos.isEmpty()) {
                    //更新缓存
                    putToCache(cartInfos, key);
                } else {
                    CartInfo cartInfo = new CartInfo();
                    redisTemplate.opsForHash().put(key, -1, JSONObject.toJSONString(cartInfo));
                    cartInfos = Collections.emptyList();
                }
            } catch (Exception e) {
                log.error("更新购物车缓存异常，key: {}, 异常信息: {}", key, e.getMessage(), e);
            } finally {
                redisTemplate.expire(key, 60 * 24, TimeUnit.MINUTES);
            }
            return cartInfos;
        } finally {
            readLock.unlock();
        }

    }

    private void putToCache(List<CartInfo> cartInfos, String key) {
        Map<String, Object> cacheCartInfo = cartInfos.stream()
                .collect(Collectors.toMap(cartInfo -> cartInfo.getSkuId().toString(), JSONObject::toJSONString));
        redisTemplate.opsForHash().putAll(key, cacheCartInfo);
    }

    /**
     * 修改购物车
     *
     * @param cartId
     * @param goodsNumber
     */
    @Override
    public void updateCart(Long cartId, Long goodsNumber) {
        String username = GmallThreadLocalUtils.getUserName();
        if (cartId == null || goodsNumber < 0) {
            throw new RuntimeException("参数错误");
        }
        LambdaQueryWrapper<CartInfo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(CartInfo::getUserId, username).eq(CartInfo::getId, cartId);
        CartInfo cartInfo = cartInfoMapper.selectOne(queryWrapper);
        if (cartInfo == null && cartInfo.getId() == null) {
            throw new RuntimeException("参数错误");
        }
        //number >0 覆盖  number=0 删除
        if (goodsNumber > 0) {
            cartInfo.setSkuNum(goodsNumber.intValue());
            int i = cartInfoMapper.updateById(cartInfo);
            if (i < 0) {
                throw new RuntimeException("修改失败");
            }
        }
        if (goodsNumber == 0) {
            int i = cartInfoMapper.deleteById(cartId);
            if (i < 0) {
                throw new RuntimeException("修改失败");
            }
        }
    }

    /**
     * 删除购物车
     *
     * @param cartId
     */
    @Override
    public void deleteCart(Long cartId) {
        String username = GmallThreadLocalUtils.getUserName();
        if (cartId == null) {
            throw new RuntimeException("参数错误");
        }
        LambdaQueryWrapper<CartInfo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(CartInfo::getUserId, username).eq(CartInfo::getId, cartId);
        //删除购物车
        int i = cartInfoMapper.delete(queryWrapper);
        if (i <= 0) {
            throw new RuntimeException("删除失败");
        }
    }

    /**
     * 选中或者取消选中，单条
     *
     * @param cartId
     * @param status 1 选中  0不选
     */
    @Override
    public void checkOrNo(Long cartId, short status) {
        String username = GmallThreadLocalUtils.getUserName();
        //id为null 全选、全不选
        if (cartId == null) {
            cartInfoMapper.checkAll(username, status);

        } else {
            //id 有值一个个选
            LambdaQueryWrapper<CartInfo> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(CartInfo::getUserId, username).eq(CartInfo::getId, cartId);
            CartInfo cartInfo = new CartInfo();
            cartInfo.setIsChecked(status);
            cartInfoMapper.update(cartInfo, queryWrapper);
        }
    }

    /**
     * 合并购物车   触发时机登录的时候通过mq触发合并
     * 此处必须添加事务 任何一个流操作失败必须全部回滚
     * @param cartInfos
     */
    @Override
    @Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRED)
    public void combineCart(List<CartInfo> cartInfos) {
        cartInfos.stream().forEach(cartInfo -> {
            this.addCart(cartInfo.getSkuId(), cartInfo.getSkuNum().longValue());
        });
    }

    /**
     * 获取订单确认信息  实际上就是已经选中的购物车信息 计算总价格
     */
    @Override
    public Map getOrderConfirmInfo() {
        String username = GmallThreadLocalUtils.getUserName();
        List<CartInfo> cartInfos = cartInfoMapper.selectList(new LambdaQueryWrapper<CartInfo>()
                .eq(CartInfo::getUserId, username)
                .eq(CartInfo::getIsChecked, CartConst.CHECK_ON));

        if (cartInfos == null || cartInfos.size() == 0) {
            return null;
        }
        //查实时价格  引入异步编排查询实时价格
        getNewSkuPrice(cartInfos);
        //计算总价格
        AtomicInteger totalNum = new AtomicInteger(0);
        cartInfos.stream().map(cartInfo -> {
            return totalNum.addAndGet(cartInfo.getSkuNum());
        }).collect(Collectors.toList());

        BigDecimal totalPrice = cartInfos.stream()
                .map(cartInfo -> cartInfo.getSkuPrice().multiply(new BigDecimal(cartInfo.getSkuNum()))
                ).reduce(BigDecimal.ZERO, (sum, price) -> sum.add(price));

        //返回前端
        HashMap<String, Object> hashMap = new HashMap<>();
        hashMap.put("totalPrice", totalPrice);
        hashMap.put("carts", cartInfos);
        hashMap.put("num", totalNum);

        return hashMap;
    }

    private void getPrice(List<CartInfo> cartInfos) {
        cartInfos.stream().map(cartInfo -> {
                    // 异步获取 skuPrice
                    CompletableFuture<BigDecimal> skuPriceFuture = CompletableFuture.supplyAsync(() ->
                                    itemFeign.getSkuPrice(cartInfo.getSkuId())
                            , threadPoolExecutor);
                    // 异步完成后设置价格
                    CompletableFuture<CartInfo> cartInfoCompletableFuture
                            = skuPriceFuture.thenApply(skuPrice -> {
                        cartInfo.setSkuPrice(skuPrice);
                        return cartInfo;
                    });
                    return cartInfoCompletableFuture;
                })
                // 收集 CompletableFuture<List<CartInfo>>
                .collect(Collectors.toList())
                .stream()
                // 等待所有异步任务完成
                .map(CompletableFuture::join)
                .collect(Collectors.toList());
    }

    private void getNewSkuPrice(List<CartInfo> cartInfos) {
        List<CompletableFuture<CartInfo>> futures = cartInfos.stream()
                .map(cartInfo -> {
                    CompletableFuture<BigDecimal> priceFuture = CompletableFuture.supplyAsync(
                            () -> itemFeign.getSkuPrice(cartInfo.getSkuId()),
                            threadPoolExecutor
                    ).exceptionally(ex -> {
                        log.error("获取sku[{}]价格失败，使用原价格: {}",
                                cartInfo.getSkuId(), cartInfo.getSkuPrice(), ex);
                        return cartInfo.getSkuPrice();
                    });

                    return priceFuture.thenApply(price -> {
                        cartInfo.setSkuPrice(price);
                        return cartInfo;
                    });
                })
                .collect(Collectors.toList());

        futures.stream()
                // 等待所有异步任务完成
                .map(cartInfoCompletableFuture -> cartInfoCompletableFuture.join())
                .collect(Collectors.toList());
    }

    /**
     * 清空购物车
     *
     * @return
     */
    @Override
    public Boolean clearCarts() {
        String username = GmallThreadLocalUtils.getUserName();
        LambdaQueryWrapper<CartInfo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(CartInfo::getUserId, username).eq(CartInfo::getIsChecked, CartConst.CHECK_ON);
        int delete = cartInfoMapper.delete(queryWrapper);
        return delete > 0;
    }

    // /**
    //  * 将购物车添加到缓存
    //  */
    // @Override
    // public void saveToRedis() {
    //     String username = GmallThreadLocalUtils.getUserName();
    //
    //     List<CartInfo> carts = this.getCarts();
    //
    //     String key = RedisConst.USER_KEY_PREFIX + username + RedisConst.USER_CART_KEY_SUFFIX;
    //     // set (user:1:cart) hset(skuId,CartInfoJson)
    //     carts.stream().forEach(cartInfo ->
    //             redisTemplate.opsForHash().put(key,
    //                     cartInfo.getSkuId(),
    //                     JSONObject.toJSONString(cartInfo)));
    //
    // }
}
